home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / Multiprocessing SDK / Sample Code / PowerFrax / sources / HFMultiprocessingPPC.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-25  |  8.2 KB  |  217 lines  |  [TEXT/CWIE]

  1. /************************************************************************************/
  2. /*                                                                                    */
  3. /* HappyFracs                                                                        */
  4. /* ----------                                                                        */
  5. /*                                                                                    */
  6. /*    © DayStar Digital, Inc. 1995-1996                                                */
  7. /*    All Rights Reserved.                                                            */
  8. /*                                                                                    */
  9. /************************************************************************************/
  10.  
  11. #include "Multiprocessing.h"
  12.  
  13. /*----------------------------------------------------------------------------------*/
  14. #define kTMCreate            1
  15. #define kTMRun                2
  16. #define kTMQuit                3
  17. #define kTMReady            4
  18.  
  19. /*----------------------------------------------------------------------------------*/
  20. typedef OSErr (*MPWorkFunction)( void *params );
  21.  
  22. typedef struct {
  23.     MPTaskID taskID;
  24.     MPQueueID appToTask;
  25.     MPQueueID taskToApp;
  26.     MPWorkFunction workFunction;
  27.     void *params;
  28.     } sTaskData, *sTaskDataPtr;
  29.  
  30. /*----------------------------------------------------------------------------------*/
  31. OSErr fMPInitialize( long *numProcessors );
  32. OSErr fMPTasksCreate( long numTasks );
  33. void fMPTaskRun( long whichTask, MPWorkFunction workFunction, void *params );
  34. void fMPTaskWait( long whichTask );
  35. void fMPTasksQuit( long numTasks );
  36. static OSStatus fTask( void *theParameter );
  37.  
  38. /*----------------------------------------------------------------------------------*/
  39. sTaskDataPtr gTaskData;            /* Task information slots                            */
  40. MPQueueID gNotificationQueue;    /* Task termination notification queue                */
  41.  
  42. /*==================================================================================*/
  43. OSErr fMPInitialize( long *numProcessors ) {
  44. /* This function is called when PowerFrax starts up. It makes sure the                */
  45. /* multiprocessing library is loaded and tells PowerFrax how many processors are    */
  46. /* available.                                                                        */
  47.  
  48.     OSErr theErr;
  49.  
  50.     theErr = noErr;
  51.  
  52.     /* Check that the MP library is present */
  53.     if( theErr == noErr )
  54.         if( !MPLibraryIsLoaded() )
  55.             theErr = 1;
  56.  
  57.     /* Get the processor count */
  58.     if( theErr == noErr )
  59.         *numProcessors = MPProcessors();
  60.  
  61.     return( theErr );
  62.     }
  63.  
  64. /*==================================================================================*/
  65. OSErr fMPTasksCreate( long numTasks ) {
  66. /* PowerFrax calls this function soon after startup and everytime the user selects    */
  67. /* a different number of processors to use from the Multiprocessing menu.            */
  68. /* It creates one communication 'slot' for each task, it creates the queues used to    */
  69. /* communicate with the task, and creates the task itself passing the address of    */
  70. /* the 'slot' to the task as its sole parameter.                                    */
  71. /* Each task is asked to acknowledge creation.                                        */
  72.  
  73.     long i;
  74.     OSErr theErr;
  75.     long message;
  76.  
  77.     theErr = noErr;
  78.  
  79.     /* Create an array of sTaskDataPtr (defined above) with one 'slot' for each        */
  80.     /* task to be created.                                                            */
  81.     gTaskData = NULL;
  82.     if( theErr == noErr ) {
  83.         gTaskData = (sTaskDataPtr)NewPtrClear( numTasks * sizeof( sTaskData ) );
  84.         if( gTaskData == NULL )
  85.             theErr = MemError();
  86.         }
  87.  
  88.     /* Create a queue by which to be notified of terminations */
  89.     gNotificationQueue = NULL;
  90.     if( theErr == noErr )
  91.         theErr = MPCreateQueue( &gNotificationQueue );
  92.  
  93.     /* Create one task per processor */
  94.     for( i = 0; i < numTasks && theErr == noErr; i++ ) {
  95.         /* Create the message queues by which to communicate the action                */
  96.         /* messages the app. sends to the tasks, and by which to receive the        */
  97.         /* status message returned by the tasks.                                    */
  98.         if( theErr == noErr )
  99.             theErr = MPCreateQueue( &gTaskData[i].appToTask );
  100.         if( theErr == noErr )
  101.             theErr = MPCreateQueue( &gTaskData[i].taskToApp );
  102.         if( theErr == noErr )
  103.             theErr = MPCreateTask( fTask, &gTaskData[i], 2048, gNotificationQueue,
  104.                 NULL, NULL, 0, &gTaskData[i].taskID );
  105.         if( theErr == noErr ) {
  106.             MPNotifyQueue( gTaskData[i].appToTask, (void *)kTMCreate, NULL, NULL );
  107.             MPWaitOnQueue( gTaskData[i].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
  108.             }
  109.         }
  110.     
  111.     return( theErr );
  112.     }
  113.  
  114. /*==================================================================================*/
  115. void fMPTaskRun( long whichTask, MPWorkFunction workFunction, void *params ) {
  116. /* Prepare data for the specified task and set it running. Normally each parameter    */
  117. /* passed to this type of function would be copied into the gTaskData block for the    */
  118. /* specified task. However, since PowerFrax provides MP services to any fractal        */
  119. /* generator that requests it, the parameters are instead passed as an arbitrary    */
  120. /* block of data. Since the parameters are different for each request PowerFrax        */
  121. /* maintains one unique block to use for each available task.                        */
  122.  
  123.     gTaskData[whichTask].workFunction = workFunction;
  124.     gTaskData[whichTask].params = params;
  125.  
  126.     MPNotifyQueue( gTaskData[whichTask].appToTask, (void *)kTMRun, NULL, NULL );
  127.     }
  128.  
  129. /*==================================================================================*/
  130. void fMPTaskWait( long whichTask ) {
  131. /* Wait until the specified task is finished doing work. PowerFrax operates by        */
  132. /* starting one scanline per task and then waiting for all of the tasks to finish.    */
  133. /* If continues to do this until the image is finished or more than a tenth of a    */
  134. /* second has elapsed. The process is repeated if necessary every time a NULL event    */
  135. /* is received in the WaitNextEvent() loop.                                            */
  136.  
  137.     long message;
  138.  
  139.     MPWaitOnQueue( gTaskData[whichTask].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
  140.     }
  141.  
  142. /*==================================================================================*/
  143. void fMPTasksQuit( long numTasks ) {
  144. /* PowerFrax calls this function before quitting and everytime the user selects a    */
  145. /* different number of processors to use from the Multiprocessing menu.                */
  146. /* The tasks are notified that they are about to be terminated. Once they            */
  147. /* acknowledge, they are terminated and all the resources they were using are        */
  148. /* deallocated.                                                                        */
  149.  
  150.     long i;
  151.     long message;
  152.  
  153.     if( gTaskData != NULL ) {
  154.         for( i = 0; i < numTasks; i++ ) {
  155.             /* If this task was successfully created then try to close it down        */
  156.             /* properly.                                                            */
  157.             if( gTaskData[i].appToTask != NULL &&
  158.                 gTaskData[i].taskToApp != NULL &&
  159.                 gTaskData[i].taskID != NULL ) {
  160.                 MPNotifyQueue( gTaskData[i].appToTask, (void *)kTMQuit, NULL, NULL );
  161.                 MPWaitOnQueue( gTaskData[i].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
  162.                 }
  163.             /* Terminate the task and wait for a termination message */
  164.             if( gTaskData[i].taskID != NULL ) {
  165.                 MPTerminateTask( gTaskData[i].taskID, noErr );
  166.                 MPWaitOnQueue( gNotificationQueue, (void **)&message, NULL, NULL, kDurationForever );
  167.                 }
  168.             /* Delete the task resources */
  169.             if( gTaskData[i].taskToApp != NULL )
  170.                 MPDeleteQueue( gTaskData[i].taskToApp );
  171.             if( gTaskData[i].appToTask != NULL )
  172.                 MPDeleteQueue( gTaskData[i].appToTask );
  173.             }
  174.         if( gNotificationQueue != NULL )
  175.             MPDeleteQueue( gNotificationQueue );
  176.         DisposePtr( (Ptr)gTaskData );
  177.         }
  178.     }
  179.  
  180. /*==================================================================================*/
  181. /*==================================================================================*/
  182. static OSStatus fTask( void *theParameter ) {
  183. /* This is the actual task. The parameter was provided at task creation time and in    */
  184. /* this case is a pointer to a 'slot' containing the information for use by this    */
  185. /* task. Note that the function that performs the actual work and the parameters to    */
  186. /* use are variables that are established in fMPTaskRun(). This lets PowerFrax        */
  187. /* provide MP services to any fractal generator willing to provide such a function.    */
  188.  
  189.     Boolean finished;
  190.     sTaskDataPtr p;
  191.     long message;
  192.  
  193.     /* The following statement is executed once, immediately after task creation */
  194.     p = (sTaskDataPtr)theParameter;
  195.  
  196.     finished = false;
  197.     while( !finished ) {
  198.         MPWaitOnQueue( p->appToTask, (void **)&message, NULL, NULL, kDurationForever );
  199.         switch( message ) {
  200.             case kTMCreate:
  201.                 break;
  202.             case kTMRun:
  203.                 p->workFunction( p->params );
  204.                 break;
  205.             case kTMQuit:
  206.                 finished = true;
  207.                 break;
  208.             }
  209.         MPNotifyQueue( p->taskToApp, (void *)kTMReady, NULL, NULL );
  210.         }
  211.  
  212.     return( noErr );
  213.     }
  214.  
  215. /*==================================================================================*/
  216. /*==================================================================================*/
  217.